/*
 * Copyright (c) 2010, Nikolaus Moll
 * All rights reserved.
 */
package net.gradecalculator.plugin.core.stux.internal;

import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Reader;
import java.io.Writer;
import java.util.LinkedList;
import java.util.List;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlElementWrapper;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlSeeAlso;
import javax.xml.bind.annotation.XmlType;

import net.gradecalculator.plugin.core.stux.internal.enums.XmlCourseTypeDescriptor;
import net.gradecalculator.plugin.core.stux.internal.enums.XmlExaminationTypeDescriptor;
import net.gradecalculator.plugin.loader.exceptions.PluginException;

@XmlRootElement(namespace = "http://gradecalculator.net/",  name = "studyRegulationsDescription")
@XmlSeeAlso({XmlModule.class, XmlIndividualModule.class, XmlSelectableModuleLists.class})
@XmlType( 
 propOrder = { "university", "degree", "semester", "courseTypes", "examTypes", "moduleList" } 
) 
public class XmlStudyRegulationsDescription  {
	private String university = "";
	private String degree = "";
	private String semester = "";
	private XmlModuleList moduleList = new XmlModuleList();

	private List<XmlCourseTypeDescriptor> courseTypes = new LinkedList<XmlCourseTypeDescriptor>();
	private List<XmlExaminationTypeDescriptor> examTypes = new LinkedList<XmlExaminationTypeDescriptor>();
	
	public String getUniversity() {
		return university;
	}
	public void setUniversity(final String university) {
		this.university = university;
	}
	
	public XmlModuleList getModuleList() {
		return moduleList;
	}
	public void setModuleList(final XmlModuleList moduleList) {
		this.moduleList = moduleList;
	}

	public String getDegree() {
		return degree;
	}
	public void setDegree(final String degree) {
		if (degree == null) {
			this.degree = "";
		} else {
			this.degree = degree;
		}
	}
	
	public String getSemester() {
		return semester;
	}
	public void setSemester(final String semester) {
		if (semester == null) {
			this.semester = "";
		} else {
			this.semester = semester;
		}
	}
	
	@XmlElementWrapper(name="coursetypes")
	@XmlElement(name = "coursetype")
	public List<XmlCourseTypeDescriptor> getCourseTypes() {
		return courseTypes;
	}
	public void setCourseTypes(final List<XmlCourseTypeDescriptor> courseTypes) {
		this.courseTypes = courseTypes;
	}
	
	@XmlElementWrapper(name="examtypes")
	@XmlElement(name = "examtype")
	public List<XmlExaminationTypeDescriptor> getExamTypes() {
		return examTypes;
	}
	public void setExamTypes(final List<XmlExaminationTypeDescriptor> examTypes) {
		
		this.examTypes = examTypes;
	}

	public static XmlStudyRegulationsDescription createFromXML(final String filename) {
		XmlStudyRegulationsDescription result = null;
		Reader xmlinput = null;
		try {
			final JAXBContext context = JAXBContext.newInstance(XmlStudyRegulationsDescription.class);
			final Unmarshaller unmarshaller = context.createUnmarshaller();
			xmlinput = new FileReader(filename);
			
			result = (XmlStudyRegulationsDescription) unmarshaller.unmarshal(xmlinput);
			//XmlTreeHelper.update(result.moduleList);
		} catch (final JAXBException jaxbException) {
			throw new PluginException("Error reading regulations xml " + filename, jaxbException);
		} catch (final Exception e) {
			throw new PluginException("Error reading regulations xml " + filename, e);
		} finally {
			try {
				if (xmlinput != null) {
					xmlinput.close();
				}
			} catch (final IOException e) {
				throw new PluginException("Error closing regulations xml", e);
			}
		}
		
		return result;
	}
	
	public void saveXML(final String filename) {
		Writer xmloutput = null;
		try {
			final JAXBContext context = JAXBContext.newInstance(XmlStudyRegulationsDescription.class);
			final Marshaller marshaller = context.createMarshaller();
			marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
			xmloutput = new FileWriter(filename);
			marshaller.marshal(this, xmloutput);
			xmloutput.flush();
		} catch (final JAXBException jaxbException) {
			throw new PluginException("Error writing regulations xml", jaxbException);
		} catch (final Exception e) {
			throw new PluginException("Error saving regulations xml", e);
		} finally {
			try {
				if (xmloutput != null) {
					xmloutput.close();
				}
			} catch (final Exception e) {
				throw new PluginException("Error closing regulations xml", e);
			}
		}
	}
}

final class XmlTreeHelper {
	private XmlTreeHelper()
	{
	}

	private static void update(final XmlModule m) {
		for (XmlCourse c : m.getCourses()) {
			c.setParent(m);
		}
	}
	
	private static void update(final XmlSelectableModuleLists sml)
	{
		for (XmlModuleList l : sml.getModuleLists()) {
			l.setParent(sml);
			update(l);
		}
	}

	public static void update(final XmlModuleList ml) {
		for (final IXmlModuleListItem imodule : ml.getModules()) {
			imodule.setParent(ml);
			if (imodule instanceof XmlIndividualModule) {
				update((XmlIndividualModule) imodule);
				continue;
			}

			if (imodule instanceof XmlSelectableModuleLists) {
				update((XmlSelectableModuleLists) imodule);
				continue;
			}

			if (imodule instanceof XmlModule) {
				update((XmlModule) imodule);
				continue;
			}
		}
	}
}

